package com.link.base.base.system.utils;

import com.link.base.base.system.model.TreeNode;
import com.link.base.core.basic.util.ThreadPoolExecutorSingleton;
import com.link.base.user.model.CoreUser;

import java.util.*;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * 生成树的工具类
 *
 * @author LiYang
 * @date 2019-12-11
 **/
public class TreeUtil {

    /**
     * 标记新增操作
     */
    public static final String INSERT_OPERATOR = "INSERT";

    /**
     * 标记更新操作
     */
    public static final String UPDATE_OPERATOR = "UPDATE";

    /**
     * 标记删除操作
     */
    public static final String DELETE_OPERATOR = "DELETE";

    /**
     * 标记缓存中的更新锁操作
     */
    public static final String UPDATE_ORG_LOCK_KEY = "updateOrgLockKey";

    /**
     * 构建多叉树
     *
     * @author LiYang
     * @date 2019/12/12
     * @param treeList 树形结构数据列表
     */
    public static List<TreeNode> buildTree(List<TreeNode> treeList) {
        if (treeList == null || treeList.size() == 0) {
            return null;
        }
        //得到根树
        List<TreeNode> trees = getRootNode(treeList);
        trees.forEach(node -> node.setDeep(0));
        List<TreeNode> parentNodes = trees;
        //声明子树
        List<TreeNode> subNodes;
        int deep = 1;
        while (true) {
            //参数treeList去掉根节点
            treeList.removeAll(parentNodes);
            //得到子节点
            subNodes = getRootNode(treeList);
            if (subNodes != null && subNodes.size() > 0) {
                for (TreeNode subNode : subNodes) {
                    subNode.setDeep(deep);
                    for (TreeNode parentNode : parentNodes) {
                        if (idEquals(parentNode.getId(), subNode.getParentId())) {
                            List<TreeNode> list = parentNode.getSubs();
                            if (list == null) {
                                list = new ArrayList<>();
                                parentNode.setSubs(list);
                            }
                            list.add(subNode);
                            subNode.setParent(parentNode);
                        }
                    }
                }
            }
            parentNodes = subNodes;
            deep++;
            if (null == subNodes) {
                break;
            }
        }
        return trees;
    }

    /**
     * 得到根节点方法
     *
     * @author LiYang
     * @date 2019/12/12
     * @param treeList 多叉树
     * @return
     */
    public static List<TreeNode> getRootNode(List<TreeNode> treeList) {
        if (treeList == null || treeList.size() == 0) {
            return null;
        }
        //得到所有的id
        List<Long> ids = treeList.stream().map(treeNode -> treeNode.getId()).collect(Collectors.toList());
        //得到根节点
        List<TreeNode> trees = treeList.stream().filter(
            node -> !ids.contains(node.getParentId()) || idEquals(node.getId(), node.getParentId()))
            .collect(Collectors.toList());
        return trees;
    }

    /**
     * 判断两个Long型数值是否相等
     *
     * @author LiYang
     * @date 2019/12/12
     * @param id
     * @param parentOrSubId
     * @return
     */
    public static boolean idEquals(Long id, Long parentOrSubId) {
        if (id == null) {
            if (parentOrSubId == null) {
                return true;
            }
        } else {
            if (parentOrSubId != null && id.equals(parentOrSubId)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 倒序遍历多叉树
     *
     * @author LiYang
     * @date 2019/12/12
     * @param treeList 多叉树
     * @param tilingMap 拉平表对应的hash
     */
    public static void backwardSequenceTraversal(List<TreeNode> treeList, Map<String, TreeNode> tilingMap) {
//        TreeNode root = treeList.get(0);
        for (TreeNode root : treeList) {
            outerLoop : while (true) {
                //从根节点进行深度遍历找到最左叶子节点
                List<TreeNode> subList = root.getSubs();
                if (null == subList || subList.size() == 0) {
                    break outerLoop;
                }
                TreeNode leafNode;
                TreeNode parentNodeTemp = new TreeNode();

                findLeafLoop : while (true) {
                    leafNode = subList.get(0);
                    if (null != leafNode.getSubs() && leafNode.getSubs().size() > 0) {
                        parentNodeTemp = leafNode;
                        subList = leafNode.getSubs();
                    } else {
                        break findLeafLoop;
                    }
                }

                if (null == parentNodeTemp.getId()) {
                    parentNodeTemp = root;
                }

                TreeNode removeNode = leafNode;
                //先与自己比较，貌似lnk_party_rel中有一条记录是自己和自己关联的
                compare(removeNode, removeNode, tilingMap);
                findParentLoop : while (true) {
                    //得到当前（叶子）节点的父节点并拼凑关系进行比较
                    TreeNode parentNode = leafNode.getParent();
                    //与父节点进行比较，修饰tilingMap对象
                    compare(removeNode, parentNode, tilingMap);
                    if (null == parentNode.getParent()) {
                        break findParentLoop;
                    }
                    leafNode = parentNode;
                }
                parentNodeTemp.getSubs().remove(removeNode);

//                if (null == root.getSubs() || root.getSubs().size() == 0) {
//                    break outerLoop;
//                }
            }
        }
    }

    /**
     * 修饰拉平表的hash，得到需要增删改的节点
     *
     * @author LiYang
     * @date 2019/12/12
     * @param tilingMap 拉平表hash
     * @return
     */
    public static Map<String, List<TreeNode>> generateOperateList(Map<String, TreeNode> tilingMap) {
        Map<String, List<TreeNode>> result = new HashMap<>(4);
        List<TreeNode> insertList = new ArrayList<>(64);
        List<TreeNode> updateList = new ArrayList<>(64);
        List<TreeNode> deleteList = new ArrayList<>(64);

        Iterator iter = tilingMap.entrySet().iterator();
        while (iter.hasNext()) {
//            Map<String, TreeNode> node = (Map<String, TreeNode>) iter.next();
            Map.Entry entry = (Map.Entry) iter.next();
            String key = (String) entry.getKey();
            TreeNode value = (TreeNode) entry.getValue();
            //这里为了不影响正常流程，如果遇到节点为空的，直接过掉
            if (null == value) {
                continue;
            }
            if (null == value.getOperation()) {
                deleteList.add(value);
                continue;
            }
            if (1 == value.getOperation().intValue()) {
                insertList.add(value);
                continue;
            }
            if (2 == value.getOperation().intValue()) {
                updateList.add(value);
                continue;
            }
        }

        result.put("insert", insertList);
        result.put("update", updateList);
        result.put("delete", deleteList);
        return result;
    }

    /**
     * 对比数据，修饰拉平表对应的hash
     *
     * @author LiYang
     * @date 2019/12/12
     * @param leafNode 当前节点
     * @param parentNode 父节点
     * @param tilingMap 拉平表对应的hash
     */
    public static void compare(TreeNode leafNode, TreeNode parentNode, Map<String, TreeNode> tilingMap) {
        String newKey = leafNode.getId().toString() + "-" + parentNode.getId();
        if (null == tilingMap) {
            tilingMap = new HashMap<>(262144);
        }
        //尝试取出当前已存在的数据
        TreeNode existsNode = tilingMap.get(newKey);
        //如果取出的数据为null，则标识之前map中不存在该数据，该数据状态改为新建
        if (null == existsNode) {
            TreeNode newNode = new TreeNode(leafNode.getId(), parentNode.getId(),
                    leafNode.getName(), parentNode.getName(), leafNode.getCode(),
                    parentNode.getCode(), leafNode.getDataType(), parentNode.getOriginType());
            //标识为新建
            newNode.setOperation(1);
            //加入map
            tilingMap.put(newKey, newNode);
            return ;
        }

        //这里对比name,code,parentName,parentCode等字段
        boolean equal = (null != leafNode.getName() && !leafNode.getName().equals(existsNode.getName()))
                || (null != leafNode.getCode() && !leafNode.getCode().equals(existsNode.getCode()))
                || (null != parentNode.getName() && !parentNode.getName().equals(existsNode.getParentName()))
                || (null != parentNode.getCode() && !parentNode.getCode().equals(existsNode.getParentCode()))
                || (null != parentNode.getOriginType() && !parentNode.getOriginType().equals(existsNode.getOriginType()));
        if (equal) {
            //标识为更新
            existsNode.setOperation(2);
            existsNode.setName(leafNode.getName());
            existsNode.setCode(leafNode.getCode());
            existsNode.setParentName(parentNode.getName());
            existsNode.setParentCode(parentNode.getCode());
            existsNode.setOriginType(parentNode.getOriginType());
        } else {
            //标识为不操作
            existsNode.setOperation(0);
        }
    }

    /**
     * 使用多线程，分别对表lnk_party_rel进行增删改查
     *
     * @author LiYang
     * @date 2019/12/13
     * @param dataMap 所需增删改的节点
     * @param dataType 类型：组织/职位 等
     * @param user 当前用户
     */
    public static void updateDataToDb(Map<String, List<TreeNode>> dataMap, String dataType, CoreUser user) {
        List<TreeNode> insertList = dataMap.get("insert");
        List<TreeNode> updateList = dataMap.get("update");
        List<TreeNode> deleteList = dataMap.get("delete");
        if (null != insertList && insertList.size() > 0) {
            ThreadPoolExecutor executor = ThreadPoolExecutorSingleton.getInstance();
            executor.execute(new PartyRelOperator(insertList, INSERT_OPERATOR, dataType, user));
        }
        if (null != updateList && updateList.size() > 0) {
            ThreadPoolExecutor executor = ThreadPoolExecutorSingleton.getInstance();
            executor.execute(new PartyRelOperator(updateList, UPDATE_OPERATOR, dataType, user));
        }
        if (null != deleteList && deleteList.size() > 0) {
            ThreadPoolExecutor executor = ThreadPoolExecutorSingleton.getInstance();
            executor.execute(new PartyRelOperator(deleteList, DELETE_OPERATOR, dataType, user));
        }
    }

    public static void main(String[] args) {
        List<TreeNode> nodeList = new ArrayList<>(16);
        nodeList.add(new TreeNode(2L, 1L, "组2", null));
        nodeList.add(new TreeNode(1L, null, "组1", null));
        nodeList.add(new TreeNode(10L, 6L, "组10", null));
        nodeList.add(new TreeNode(6L, 2L, "组6", null));
        nodeList.add(new TreeNode(8L, 4L, "组8", null));
        nodeList.add(new TreeNode(3L, 1L, "组3", null));
        nodeList.add(new TreeNode(7L, 3L, "组7", null));
        nodeList.add(new TreeNode(5L, 2L, "组5", null));
        nodeList.add(new TreeNode(4L, 1L, "组4", null));
        nodeList.add(new TreeNode(9L, 7L, "组9", null));

        Map<String, TreeNode> tilingMap = new HashMap<>(8);
        tilingMap.put("5-1", new TreeNode(5L, 1L, "组5", "组1"));
        tilingMap.put("10-2", new TreeNode(10L, 2L, "组10", "组2"));
        tilingMap.put("9-3", new TreeNode(9L, 3L, "组9", "----测试更新----"));
        tilingMap.put("9-8", new TreeNode(9L, 8L, "组9", "组8"));
        tilingMap.put("8-1", new TreeNode(8L, 1L, "组8", "组1"));
        tilingMap.put("2-1", new TreeNode(2L, 1L, "组2", "组1"));

        List<TreeNode> treeList = buildTree(nodeList);

        backwardSequenceTraversal(treeList, tilingMap);
    }
}
